/**************************************************************************************
*  Eeprom.java
*  Program demonstrating the use of I2C to access EEPROM with LPC21xx.
**************************************************************************************
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL RTJ COMPUTING BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Created by:
*      RTJ Computing
**************************************************************************************/
import lpc2xxx.comm.*;
import lpc2xxx.hw.*;


class Eeprom
{
    private final static int devAddr = 0xA0;
    private final static int eeSize = 0x100;   // 256 bytes (2 kbit)
    private static String outRange = "Entered values are outside memory range";
    private static String eeFail = "EE read/write fail";
    private static String usrBreak = "\nUser break";
    private I2C iic;
    private static Eeprom ee;

    static void main(String[] args) 
    {
        Console.println("");
        Console.println("LPC21xx I2C 2kbit EEPROM demo");
        Console.println("This program is for use with LPC2148 Education board");
        Console.println("Jumper settings:");
        Console.println("  connect    J10,J11\r\n");

        I2C.init(100000);
        ee = new Eeprom();
        showMenu();
        while (true)
        {
            char key = Console.getKey();
            if (key == Console.ESC)
                break;

            switch (key)
            {
                case '1':
                    writeText();
                    showMenu();
                    break;
                case '2':
                    dumpMem();
                    showMenu();
                    break;
                case '3':
                    clearMem();
                    showMenu();
                    break;
            }
        }
    }

    static int getHexInput(String text)
    {
        int val = -1;
        Console.print(text);
        try 
        {
            String in = Console.getKeys();
            Console.println("");
            if (in != null)
                val = Integer.parseInt(in, 16);
        }
        catch (NumberFormatException e)
        {
            Console.println("Invalid numeric value");
        }
        return val;
    }

    static void showMenu()
    {
        Console.println("");
        Console.println("Press:");
        Console.println("   1   - write text string");
        Console.println("   2   - dump memory range");
        Console.println("   3   - clear memory range");
        Console.println("   ESC - exit program");
    }

    static void writeText()
    {
        Console.println("\nWrite text");
        int addr = getHexInput("Enter start address: 0x");
        if (addr != -1)
        {
            Console.print("Enter text: ");
            String text = Console.getKeys();
            Console.println("");
            if (text != null && text.length() > 0)
            {
                if (addr + text.length() > eeSize)
                    Console.println(outRange);
                else
                {
                    if (!ee.write(addr, text))
                        Console.println(eeFail);
                    else
                        Console.print("Success");
                }
            }
        }
        Console.println("");
    }

    static char toHex(byte v)
    {
        v &= 0xF;
        if (v <= 9)
            return (char)(v + 0x30);
        return (char)(v + 0x37);
    }

    static void toHex2(byte v)
    {
        Console.putch(toHex((byte)(v >> 4)));
        Console.putch(toHex(v));
    }

    static void toHex4(int v)
    {
        toHex2((byte)(v >> 8));
        toHex2((byte)(v & 0xFF));
    }

    static void dumpMem()
    {
        Console.println("\nMemory dump");
        int addr = getHexInput("Enter start address: 0x");
        if (addr != -1)
        {
            int len = getHexInput("Enter length: 0x");
            if (len != -1)
            {
                if (addr + len > eeSize)
                    Console.println(outRange);
                else
                {
                    byte[] data = new byte[16];
                    int count = 0;
                    while (len > 0)
                    {
                        if (Console.keyAvail() && Console.getKey() == Console.ESC)
                        {
                            Console.println(usrBreak);
                            break;
                        }

                        int blockLen = len > data.length ? data.length : len;
                        if (!ee.read(addr, data, 0, blockLen))
                        {
                            Console.println(eeFail);
                            break;
                        }
                        toHex4(addr);
                        Console.print(": ");
                        for (int i=0; i < blockLen; i++)
                        {
                            toHex2(data[i]);
                            Console.putch(' ');
                        }
                        Console.print("   ");
                        for (int i=0; i < blockLen; i++)
                            Console.putch(data[i] >= 0x20 && data[i] <= 0x7F ? (char)data[i] : '.');
                        Console.println("");
                        addr += blockLen;
                        len -= blockLen;
                    }
                }
            }
        }
        Console.println("");
    }

    static void clearMem()
    {
        Console.println("\nClear memory");
        int addr = getHexInput("Enter start address: 0x");
        if (addr != -1)
        {
            int len = getHexInput("Enter length: 0x");
            if (len != -1)
            {
                if (addr + len > eeSize)
                    Console.println(outRange);
                else
                {
                    int val = getHexInput("Enter value to write: 0x");
                    if (val != -1)
                    {
                        byte[] data = new byte[16];
                        for (int i=0; i < data.length; i++)
                            data[i] = (byte)val;

                        while (len > 0)
                        {
                            if (Console.keyAvail() && Console.getKey() == Console.ESC)
                            {
                                Console.println(usrBreak);
                                break;
                            }
    
                            Console.print("\rWriting: 0x");
                            toHex4(addr);
                            int blockLen = len > data.length ? data.length : len;
                            if (!ee.write(addr, data, 0, blockLen))
                            {
                                Console.println(eeFail);
                                break;
                            }
                            addr += blockLen;
                            len -= blockLen;
                        }
                        Console.print("\rWriting: 0x");
                        toHex4(addr);
                    }
                }
            }
        }
        Console.println("");
    }

    // EEPROM object constructor
    Eeprom()
    {
        iic = new I2C(devAddr);
    }

    // read data from EEPROM into destination array
    boolean read(int addr, byte[] dest, int offs, int len)
    {
        boolean rv = false;
        if (iic.write(dest, (byte)addr, 0, 0))
        {
            if (iic.reStart() == I2C.OK)
                rv = iic.read(dest, offs, len) == I2C.OK;
        }
        iic.stop();
        return rv;
    }

    // write data from source array into EEPROM
    boolean write(int addr, byte[] src, int offs, int len)
    {
        boolean rv = true;
        while (len-- > 0)
        {
            rv = iic.write(src, (byte)addr++, offs++, 1);
            iic.stop();
            if (!rv || !iic.poll())
            {
                rv = false;
                break;
            }
        }
        return rv;
    }
    
    // write data from String into EEPROM
    boolean write(int addr, String text)
    {
        byte[] data = text.getBytes();
        return write(addr, data, 0, data.length);
    }
}

